package com.winsdom.service.impl;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.winsdom.context.BaseContext;
import com.winsdom.domain.vo.BuildingResourceVO;
import com.winsdom.dto.CategoryTreeNodes;
import com.winsdom.dto.threeTables.ThreeTablesDto;
import com.winsdom.entity.*;
import com.winsdom.exception.BaseException;
import com.winsdom.mapper.*;
import com.winsdom.result.PageResult;
import com.winsdom.result.Result;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.winsdom.domain.vo.FinishedThreeTableVO;
import com.winsdom.domain.vo.UnfinishedThreeTableVO;
import com.winsdom.entity.ThreeTables;
import com.winsdom.mapper.CategoryMapper;
import com.winsdom.mapper.ThreeTablesMapper;
import com.winsdom.service.ICategoryService;
import com.winsdom.service.IThreeTablesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winsdom.utils.QRCodeUtil;
import com.winsdom.vo.threeTables.ThreeTablesVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.List;


/**
 * <p>
 * 三表表 服务实现类
 * </p>
 *
 * @author 
 * @since 2025-05-12
 */
@Slf4j
@Service
public class ThreeTablesServiceImpl extends ServiceImpl<ThreeTablesMapper, ThreeTables> implements IThreeTablesService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private ReadingRecordMapper readingRecordMapper;
    @Autowired
    private BillingConfigMapper billingConfigMapper;
    @Autowired
    private UserProjectsMapper userProjectsMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ThreeTablesMapper threeTablesMapper;
    @Autowired
    private ICategoryService iCategoryService;

    @Override
    public Result getResourceTree() {
        //获取当前账号下已授权的楼盘的资源信息
        Integer userId = BaseContext.getCurrentId();
        SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, userId));
        List<UserProjects> userProjects = userProjectsMapper.selectList(new LambdaQueryWrapper<UserProjects>()
                .eq(UserProjects::getUserId, userId));
        List<Long> ids = userProjects.stream().map(userProject -> userProject.getCategoryId()).collect(Collectors.toList());

        List<CategoryTreeNodes> resourceTree = getAuthorizedResourceTree(sysUser.getCategoryId(), new HashSet<>(ids));

        return Result.success(resourceTree);
    }


    public List<CategoryTreeNodes> getAuthorizedResourceTree(Long orgId, Set<Long> authorizedBuildingIds) {
        // 1. 查询所有分类数据
        List<Category> allCategories = categoryMapper.selectList(new LambdaQueryWrapper<Category>().eq(Category::getStatus, 1));

        // 2. 转换为节点映射
        Map<Long, CategoryTreeNodes> idNodeMap = new HashMap<>();
        for (Category category : allCategories) {
            CategoryTreeNodes node = new CategoryTreeNodes();
            BeanUtils.copyProperties(category, node);
            node.setChildren(new ArrayList<>());
            idNodeMap.put(node.getId(), node);
        }

        // 3. 构建父子关系
        for (CategoryTreeNodes node : idNodeMap.values()) {
            CategoryTreeNodes parent = idNodeMap.get(node.getParentId());
            if (parent != null) {
                parent.getChildren().add(node);
            }
        }

        //  4. 从 orgId 本身作为根节点开始过滤
        CategoryTreeNodes root = idNodeMap.get(orgId);
        if (root == null) {
            return Collections.emptyList(); // orgId 不存在
        }

        CategoryTreeNodes filtered = filterResourceUnderAuthorizedBuildings(root, authorizedBuildingIds);
        if (filtered == null) {
            return Collections.emptyList(); // 无授权资源
        }

        //  返回带 orgId 的整棵子树
        return Collections.singletonList(filtered);
    }
    private CategoryTreeNodes filterResourceUnderAuthorizedBuildings(CategoryTreeNodes node, Set<Long> authorizedBuildingIds) {
        if (node.getType() == 3 && !authorizedBuildingIds.contains(node.getId())) {   //是否在楼盘ID集合中
            return null;
        }

        List<CategoryTreeNodes> newChildren = new ArrayList<>();
        for (CategoryTreeNodes child : node.getChildren()) {
            CategoryTreeNodes filteredChild = filterResourceUnderAuthorizedBuildings(child, authorizedBuildingIds);
            if (filteredChild != null) {
                newChildren.add(filteredChild);
            }
        }

        node.setChildren(newChildren);

        if (node.getType() == 6 || !newChildren.isEmpty()) {   //type=6  资源
            return node;
        }

        return null;
    }

    @Override
    public Result getList(ThreeTablesDto threeTablesDto) {
        if(threeTablesDto.getCategoryId()==null){
            return Result.success();
        }
        int num = (threeTablesDto.getPageNum() - 1) * threeTablesDto.getPageSize();
        int temp=threeTablesDto.getPageNum();
        threeTablesDto.setPageNum(num);
        List<ThreeTablesVo> list=threeTablesMapper.getListForParams(threeTablesDto);
        for(ThreeTablesVo threeTablesVo:list){
            String fullPathFromResource = getFullPathFromResource(Long.valueOf(threeTablesVo.getCategoryId()));
            threeTablesVo.setResourceName(fullPathFromResource);
        }
        Integer count = threeTablesMapper.selectCount(new LambdaQueryWrapper<ThreeTables>().eq(ThreeTables::getCategoryId, threeTablesDto.getCategoryId()));
        return Result.success(new PageResult(count,list,temp,threeTablesDto.getPageSize()));
    }


    /**
     * 查询当前最顶层到资源的全名称 比如：海王星大厦/A栋/1层/101
     * @param resourceId
     * @return
     */
    public String getFullPathFromResource(Long resourceId) {
        // 1. 获取所有分类数据（可加缓存优化）
        List<Category> all = categoryMapper.selectList(null);
        Map<Long, Category> idMap = all.stream()
                .collect(Collectors.toMap(Category::getId, Function.identity()));

        // 2. 从当前资源向上递归拼接
        List<String> namePath = new ArrayList<>();

        Long currentId = resourceId;
        while (currentId != null) {
            Category current = idMap.get(currentId);
            if (current == null) break;

            namePath.add(current.getName());
            currentId = current.getParentId(); // 一直递归到 parentId == null 为止
        }

        // 3. 倒序拼接为全路径
        Collections.reverse(namePath);
        return String.join("/", namePath);
    }


    @Override
    public Result add(ThreeTables threeTables) {
        //比如：SELECT * FROM three_tables WHERE category_id = 19 AND (name = 'S101水表' OR number = 'S101')
        ThreeTables threeTables2 = threeTablesMapper.selectOne(
                new LambdaQueryWrapper<ThreeTables>()
                        .eq(ThreeTables::getCategoryId, threeTables.getCategoryId())  // category_id=19（必须）
                        .and(wrapper -> wrapper
                                .eq(ThreeTables::getName, threeTables.getName())      // name='S101水表'
                                .or()
                                .eq(ThreeTables::getNumber, threeTables.getNumber())   // OR number='S101'
                        )
        );
        if(threeTables2!=null){
            return Result.error("该三表编号，三表名称已存在!");
        }
        Integer count = threeTablesMapper.selectCount(new LambdaQueryWrapper<ThreeTables>().eq(ThreeTables::getCategoryId, threeTables.getCategoryId()).eq(ThreeTables::getStatus,1));
        if(count>=100){
            return Result.error("该资源下三表数量已达上限，请先停用后重试!");
        }

        Integer userId = BaseContext.getCurrentId();
        threeTables.setUserId(Long.valueOf(userId));
        threeTables.setReadingCycle("每月一次");
        threeTables.setStatus(1);
        threeTables.setCreateTime(LocalDateTime.now());
        threeTables.setUpdateTime(LocalDateTime.now());
        threeTablesMapper.insert(threeTables);
        return Result.success();
    }

    @Override
    public Result updateThreeTables(ThreeTables threeTables) {
        ThreeTables threeTables2 = threeTablesMapper.selectOne(
                new LambdaQueryWrapper<ThreeTables>()
                        .and(wrapper -> wrapper
                                .eq(ThreeTables::getName, threeTables.getName())      // name='S101水表'
                                .or()
                                .eq(ThreeTables::getNumber, threeTables.getNumber())   // OR number='S101'
                        )
        );
        if(threeTables2!=null && threeTables2.getId()!=threeTables.getId()){
            return Result.error("该三表编号，三表名称已存在!");
        }
        Integer userId = BaseContext.getCurrentId();
        threeTables.setUserId(Long.valueOf(userId));
        threeTables.setUpdateTime(LocalDateTime.now());
        threeTablesMapper.updateById(threeTables);
        return Result.success();
    }

    @Override
    public Result delete(Integer id) {
        List<ReadingRecord> readingRecords = readingRecordMapper.selectList(new LambdaQueryWrapper<ReadingRecord>().eq(ReadingRecord::getTableId, id));
        if (readingRecords != null && !readingRecords.isEmpty()) {
            return Result.error("该表已有抄表数据!");
        }
        List<BillingConfig> billingConfigs = billingConfigMapper.selectList(new LambdaQueryWrapper<BillingConfig>().eq(BillingConfig::getTableId, id));
        if(billingConfigs!=null && billingConfigs.size()>0){
            return Result.error("已跟计费项目关联!");
        }
        threeTablesMapper.deleteById(id);
        return Result.success();
    }

    @Override
    public Result getQRcode(Integer id) {
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        String qrCode = null;
        try {
            qrCode = qrCodeUtil.createQRCode("http://192.168.240.132:8080/orders/alipaytest", 200, 200);
        } catch (IOException e) {
            new BaseException("生成二维码失败");
        }
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("qrCode", qrCode);
        return Result.success(hashMap);
    }
    @Override
    public Result getBatchQRcode(List<Integer> ids) {
        List<String> qrCodes = new ArrayList<>();
        for (Integer id : ids) {
            QRCodeUtil qrCodeUtil = new QRCodeUtil();
            String qrCode = null;
            try {
                qrCode = qrCodeUtil.createQRCode(String.format("http://192.168.240.132:8080/orders/alipaytest?id=%d", id), 200, 200);
                qrCodes.add(qrCode);
            } catch (IOException e) {
                new BaseException("生成二维码失败");
            }
        }
        return Result.success(qrCodes);
    }

    @Override
    public Page<FinishedThreeTableVO> getFinishedThreeTables(Long pageNum, Long pageSize, Long resourceId,Long buildingId, String number, Integer type) {
        // 初始化分页对象
        Page<FinishedThreeTableVO> page = new Page<>(pageNum, pageSize);
        Page<FinishedThreeTableVO> finishedThreeTableVOPage =null;
        if(resourceId!=null){
            finishedThreeTableVOPage = threeTablesMapper.getFinishedThreeTables(page, resourceId, number, type);
        }else {
            List<BuildingResourceVO> buildingResource = iCategoryService.getBuildingResource(buildingId);
            // 获取 id 列表
            List<Long> idList = buildingResource.stream()
                    .map(BuildingResourceVO::getId)
                    .collect(Collectors.toList());
            finishedThreeTableVOPage=threeTablesMapper.getFinishedThreeTables2(page,idList,number,type);
        }

        for (FinishedThreeTableVO finishedThreeTableVO : finishedThreeTableVOPage.getRecords()) {
            if (finishedThreeTableVO != null) {
                String parent=categoryMapper.getParent(finishedThreeTableVO.getCategoryId());
//                System.out.println(parent);
                String[] s = parent.split(" ");
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = s.length; i >0 ; i--) {
                    stringBuilder.append(s[i-1]);
                    if(i!=1){
                        stringBuilder.append("/");
                    }
                }
                finishedThreeTableVO.setResource(String.valueOf(stringBuilder));
            }
        }

        return finishedThreeTableVOPage;
    }
    @Override
    public Page<UnfinishedThreeTableVO> getUnfinishedThreeTables(Long pageNum, Long pageSize, Long resourceId,Long buildingId, String number, Integer type) {
        // 初始化分页对象
        Page<UnfinishedThreeTableVO> page = new Page<>(pageNum, pageSize);

        Page<UnfinishedThreeTableVO> unfinishedThreeTables=null;
        if(resourceId!=null){
            unfinishedThreeTables = threeTablesMapper.getUnfinishedThreeTables(page, resourceId, number, type);
        }else {
            List<BuildingResourceVO> buildingResource = iCategoryService.getBuildingResource(buildingId);
            // 获取 id 列表
            List<Long> idList = buildingResource.stream()
                    .map(BuildingResourceVO::getId)
                    .collect(Collectors.toList());
            unfinishedThreeTables=threeTablesMapper.getUnfinishedThreeTables2(page,idList,number,type);
        }

        for (UnfinishedThreeTableVO unfinishedThreeTableVO : unfinishedThreeTables.getRecords()) {
            if (unfinishedThreeTableVO != null) {
                String parent=categoryMapper.getParent(unfinishedThreeTableVO.getCategoryId());
//                System.out.println(parent);
                String[] s = parent.split(" ");
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = s.length; i >0 ; i--) {
                    stringBuilder.append(s[i-1]);
                    if(i!=1){
                        stringBuilder.append("/");
                    }
                }
                unfinishedThreeTableVO.setResource(String.valueOf(stringBuilder));
            }
        }

        return unfinishedThreeTables;
    }

    @SneakyThrows
    @Override
    public void getAllFinishedThreeTablesByBuilding(HttpServletResponse response,Long buildingId) {
        List<BuildingResourceVO> buildingResource = iCategoryService.getBuildingResource(buildingId);
        // 获取 id 列表
        List<Long> idList = buildingResource.stream()
                .map(BuildingResourceVO::getId)
                .collect(Collectors.toList());
        List<FinishedThreeTableVO> finishedThreeTables = threeTablesMapper.getFinishedThreeTables2(idList, null, null);
        for (FinishedThreeTableVO finishedThreeTableVO : finishedThreeTables) {
            if (finishedThreeTableVO != null) {
                String parent=categoryMapper.getParent(finishedThreeTableVO.getCategoryId());
                String[] s = parent.split(" ");
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = s.length; i >0 ; i--) {
                    stringBuilder.append(s[i-1]);
                    if(i!=1){
                        stringBuilder.append("/");
                    }
                }
                finishedThreeTableVO.setResource(String.valueOf(stringBuilder));
            }
        }

        ExcelWriter excelWriter = ExcelUtil.getWriter(true);
        log.info("已抄表导出数据：{}", finishedThreeTables);

        List<Map<String, Object>> list = new ArrayList<>();
        int i = 1;
        for (FinishedThreeTableVO finishedThreeTableVO : finishedThreeTables) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("序号", i);
            map.put("三表性质", finishedThreeTableVO.getType());
            map.put("三表编号", finishedThreeTableVO.getNumber());
            map.put("三表名称", finishedThreeTableVO.getName());
            map.put("所属资源", finishedThreeTableVO.getResource());
            map.put("抄表周期", finishedThreeTableVO.getReadingCycle());
            map.put("上期抄表时间", finishedThreeTableVO.getLastReadTime());
            map.put("上期读数", finishedThreeTableVO.getLastReading());
            map.put("上期用量", finishedThreeTableVO.getLastUse());
            map.put("本期抄表时间", finishedThreeTableVO.getReadTime());
            map.put("本期读数", finishedThreeTableVO.getCurrentReading());
            map.put("本期用量", finishedThreeTableVO.getCurrentUse());
            map.put("状态", finishedThreeTableVO.getStatus() == 1 ? "已计费" : "未计费");
            list.add(map);
            i++;
        }
        // 将数据写入Excel
        excelWriter.write(list, true);
        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String filename = URLEncoder.encode("已抄表数据详情", StandardCharsets.UTF_8) + ".xlsx";
        response.setHeader("Content-Disposition", "attachment; filename=" + filename);
        // 获取Servlet输出流并写入数据
        ServletOutputStream outputStream = response.getOutputStream();
        excelWriter.flush(outputStream, true);
        excelWriter.close();
        outputStream.flush();
        outputStream.close();
    }

}
